//
//  BenchmarkTestCase.m
//  GCDBenchmark
//
//  Created by Claude on 2025/10/13.
//

#import "BenchmarkTestCase.h"
#import <dispatch/dispatch.h>

NSString * const kParamTaskType = @"taskType";
NSString * const kParamTaskCount = @"taskCount";
NSString * const kParamTaskDuration = @"taskDuration";
NSString * const kParamQoS = @"taskQoS";
NSString * const kParamBufferCount = @"bufferCount";
NSString * const kParamSliceCount = @"sliceCount";
NSString * const kParamMaxConcurrency = @"maxConcurrency";
NSString * const kParamSubmitInterval = @"submitInterval";
NSString * const kParamPeriod = @"period";
NSString * const kParamRunDuration = @"runDuration";
NSString * const kParamFibDepth = @"fibDepth";
NSString * const kParamSelectedFileName = @"selectedFileName";

static NSString *TaskTypeName(NSNumber *value) {
    switch (value.integerValue) {
        case 0: return @"CPU";
        case 1: return @"IO";
        case 2: return @"Suspend";
        default: return [NSString stringWithFormat:@"类型%@", value];
    }
}

static NSString *QoSName(NSNumber *value) {
    switch (value.integerValue) {
        case QOS_CLASS_DEFAULT: return @"Default";
        case QOS_CLASS_USER_INITIATED: return @"UserInitiated";
        case QOS_CLASS_USER_INTERACTIVE: return @"UserInteractive";
        case QOS_CLASS_BACKGROUND: return @"Background";
        case QOS_CLASS_UTILITY: return @"Utility";
        case QOS_CLASS_UNSPECIFIED: return @"Unspecified";
        default: return [NSString stringWithFormat:@"QoS(%ld)", (long)value.integerValue];
    }
}

static NSString *FormatMicroseconds(NSInteger microseconds) {
    if (microseconds >= 1000) {
        double ms = microseconds / 1000.0;
        return [NSString stringWithFormat:@"%.2fms", ms];
    }
    return [NSString stringWithFormat:@"%ldus", (long)microseconds];
}

static NSString *FormatMilliseconds(NSInteger microseconds) {
    if (microseconds >= 1000) {
        double ms = microseconds / 1000.0;
        return [NSString stringWithFormat:@"%.2fms", ms];
    }
    return [NSString stringWithFormat:@"%ldus", (long)microseconds];
}

@implementation BenchmarkTestCase

- (instancetype)initWithType:(BenchmarkTestCaseType)type
                        name:(NSString *)name
                        icon:(NSString *)icon {
    self = [super init];
    if (self) {
        _type = type;
        _name = name;
        _icon = icon;
        _customParams = [NSMutableDictionary dictionary];
        [self loadDefaultParams];
    }
    return self;
}

- (void)loadDefaultParams {
    NSDictionary *defaults = @{};

    switch (self.type) {
        case BenchmarkTestCaseTypeForkJoin:
            defaults = @{
                kParamTaskType: @(0),
                kParamTaskCount: @(512),
                kParamTaskDuration: @(100),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        case BenchmarkTestCaseTypeFibonacci:
            defaults = @{
                kParamTaskType: @(0),
                kParamTaskDuration: @(100),
                kParamFibDepth: @(10),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        case BenchmarkTestCaseTypeAriawSemaphore:
        case BenchmarkTestCaseTypeAriawNSOperation:
            defaults = @{
                kParamTaskType: @(0),
                kParamBufferCount: @(4),
                kParamSliceCount: @(512),
                kParamTaskDuration: @(200),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        case BenchmarkTestCaseTypeConcurrentQueue:
            defaults = @{
                kParamTaskType: @(0),
                kParamTaskCount: @(512),
                kParamTaskDuration: @(1000),
                kParamMaxConcurrency: @(4),
                kParamSubmitInterval: @(100),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        case BenchmarkTestCaseTypePeriodicTasks:
            defaults = @{
                kParamTaskType: @(0),
                kParamPeriod: @(10000),       // 10ms in microseconds
                kParamTaskCount: @(100),
                kParamTaskDuration: @(100),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        case BenchmarkTestCaseTypePlayback:
            defaults = @{
                kParamSelectedFileName: @""
            };
            break;

        case BenchmarkTestCaseTypeSerialQueue:
            defaults = @{
                kParamTaskType: @(0),
                kParamTaskCount: @(512),
                kParamTaskDuration: @(10),
                kParamSubmitInterval: @(100),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;

        default:
            defaults = @{
                kParamTaskType: @(0),
                kParamTaskCount: @(512),
                kParamTaskDuration: @(100),
                kParamQoS: @(QOS_CLASS_DEFAULT)
            };
            break;
    }

    [self.customParams addEntriesFromDictionary:defaults];

    NSDictionary *saved = [[NSUserDefaults standardUserDefaults] dictionaryForKey:[self userDefaultsKeyPrefix]];
    if (saved) {
        [self.customParams addEntriesFromDictionary:saved];
    }
}

- (NSString *)parameterDescription {
    NSMutableArray *params = [NSMutableArray array];

    switch (self.type) {
        case BenchmarkTestCaseTypeForkJoin: {
            NSNumber *taskType = self.customParams[kParamTaskType];
            NSNumber *taskCount = self.customParams[kParamTaskCount];
            NSNumber *taskDuration = self.customParams[kParamTaskDuration];
            NSNumber *qos = self.customParams[kParamQoS];
            if (taskType) [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(taskType)]];
            if (taskCount) [params addObject:[NSString stringWithFormat:@"数量: %@", taskCount]];
            if (taskDuration) [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds(taskDuration.integerValue)]];
            if (qos) [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(qos)]];
            break;
        }

        case BenchmarkTestCaseTypeFibonacci:
            [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(self.customParams[kParamTaskType] ?: @(0))]];
            [params addObject:[NSString stringWithFormat:@"深度: %@", self.customParams[kParamFibDepth] ?: @(10)]];
            [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds([self.customParams[kParamTaskDuration] integerValue])]];
            [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(self.customParams[kParamQoS] ?: @(QOS_CLASS_DEFAULT))]];
            break;

        case BenchmarkTestCaseTypeAriawNSOperation:
        case BenchmarkTestCaseTypeAriawSemaphore: {
            NSNumber *bufferCount = self.customParams[kParamBufferCount];
            NSNumber *sliceCount = self.customParams[kParamSliceCount];
            NSNumber *taskDuration = self.customParams[kParamTaskDuration];
            NSNumber *taskType = self.customParams[kParamTaskType];
            NSNumber *qos = self.customParams[kParamQoS];
            if (taskType) [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(taskType)]];
            if (bufferCount) [params addObject:[NSString stringWithFormat:@"缓冲区: %@", bufferCount]];
            if (sliceCount) [params addObject:[NSString stringWithFormat:@"Slice: %@", sliceCount]];
            if (taskDuration) [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds(taskDuration.integerValue)]];
            if (qos) [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(qos)]];
            break;
        }

        case BenchmarkTestCaseTypeSerialQueue: {
            NSNumber *taskType = self.customParams[kParamTaskType];
            NSNumber *taskCount = self.customParams[kParamTaskCount];
            NSNumber *taskDuration = self.customParams[kParamTaskDuration];
            NSNumber *submitInterval = self.customParams[kParamSubmitInterval];
            NSNumber *qos = self.customParams[kParamQoS];
            if (taskType) [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(taskType)]];
            if (taskCount) [params addObject:[NSString stringWithFormat:@"数量: %@", taskCount]];
            if (taskDuration) [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds(taskDuration.integerValue)]];
            if (submitInterval) [params addObject:[NSString stringWithFormat:@"间隔: %@", FormatMicroseconds(submitInterval.integerValue)]];
            if (qos) [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(qos)]];
            break;
        }

        case BenchmarkTestCaseTypeConcurrentQueue: {
            NSNumber *taskType = self.customParams[kParamTaskType];
            NSNumber *taskCount = self.customParams[kParamTaskCount];
            NSNumber *taskDuration = self.customParams[kParamTaskDuration];
            NSNumber *maxConcurrency = self.customParams[kParamMaxConcurrency];
            NSNumber *submitInterval = self.customParams[kParamSubmitInterval];
            NSNumber *qos = self.customParams[kParamQoS];
            if (taskType) [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(taskType)]];
            if (taskCount) [params addObject:[NSString stringWithFormat:@"数量: %@", taskCount]];
            if (taskDuration) [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds(taskDuration.integerValue)]];
            if (maxConcurrency) [params addObject:[NSString stringWithFormat:@"并发度: %@", maxConcurrency]];
            if (submitInterval) [params addObject:[NSString stringWithFormat:@"间隔: %@", FormatMicroseconds(submitInterval.integerValue)]];
            if (qos) [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(qos)]];
            break;
        }

        case BenchmarkTestCaseTypePeriodicTasks: {
            NSInteger period = [self.customParams[kParamPeriod] integerValue];
            NSNumber *taskCount = self.customParams[kParamTaskCount];
            NSNumber *taskDuration = self.customParams[kParamTaskDuration];
            NSNumber *taskType = self.customParams[kParamTaskType];
            NSNumber *qos = self.customParams[kParamQoS];
            if (taskType) [params addObject:[NSString stringWithFormat:@"类型: %@", TaskTypeName(taskType)]];
            [params addObject:[NSString stringWithFormat:@"周期: %@", FormatMilliseconds(period)]];
            if (taskCount) [params addObject:[NSString stringWithFormat:@"次数: %@", taskCount]];
            if (taskDuration) [params addObject:[NSString stringWithFormat:@"时长: %@", FormatMicroseconds(taskDuration.integerValue)]];
            if (qos) [params addObject:[NSString stringWithFormat:@"QoS: %@", QoSName(qos)]];
            break;
        }

        case BenchmarkTestCaseTypePlayback: {
            NSString *selectedFile = self.customParams[kParamSelectedFileName];
            if (selectedFile && selectedFile.length > 0) {
                [params addObject:[NSString stringWithFormat:@"文件: %@", selectedFile]];
            } else {
                [params addObject:@"未选择文件"];
            }
            break;
        }

        default:
            break;
    }

    return [params componentsJoinedByString:@" | "];
}

- (NSString *)userDefaultsKeyPrefix {
    NSString *prefix = @"kTestCase";
    switch (self.type) {
        case BenchmarkTestCaseTypeForkJoin:
            return [prefix stringByAppendingString:@"ForkJoin"];
        case BenchmarkTestCaseTypeFibonacci:
            return [prefix stringByAppendingString:@"Fibonacci"];
        case BenchmarkTestCaseTypeAriawNSOperation:
            return [prefix stringByAppendingString:@"AriawNS"];
        case BenchmarkTestCaseTypeAriawSemaphore:
            return [prefix stringByAppendingString:@"AriawSem"];
        case BenchmarkTestCaseTypeSerialQueue:
            return [prefix stringByAppendingString:@"Serial"];
        case BenchmarkTestCaseTypeConcurrentQueue:
            return [prefix stringByAppendingString:@"Concurrent"];
        case BenchmarkTestCaseTypePeriodicTasks:
            return [prefix stringByAppendingString:@"Periodic"];
        case BenchmarkTestCaseTypePlayback:
            return [prefix stringByAppendingString:@"Playback"];
    }
}

- (void)persistCustomParams {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:[self.customParams copy] forKey:[self userDefaultsKeyPrefix]];
    [defaults synchronize];
}

@end
